package com.shawn.server.service;

import cn.hutool.core.collection.CollUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.shawn.autoconfig.template.OssTemplate;
import com.shawn.commons.utils.CommentType;
import com.shawn.commons.utils.RC;
import com.shawn.dubbo.api.UserInfoApi;
import com.shawn.dubbo.api.VideoApi;
import com.shawn.model.entity.UserInfo;
import com.shawn.model.mongo.Video;
import com.shawn.model.vo.CommentsVo;
import com.shawn.model.vo.ErrorResult;
import com.shawn.model.vo.PageResult;
import com.shawn.model.vo.VideoVo;
import com.shawn.server.exception.BusinessException;
import com.shawn.server.interceptor.ThreadContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class VideoService {

    @Autowired
    private CommentsService commentsService;

    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private FdfsWebServer webServer;

    @Autowired //图片存储至阿里云
    private OssTemplate ossTemplate;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private MqMessageService messageService;

    @DubboReference
    private VideoApi videoApi;

    @DubboReference
    private UserInfoApi userInfoApi;


    /**
     * 发布视频
     *
     * @param userId         用户id
     * @param videoThumbnail 视频缩略图
     * @param videoFile      视频文件
     * @throws IOException ioexception
     *
     */
    @CacheEvict(value = "recommendVideo",allEntries = true) //发布视频后删除所有视频缓存
    public void publishVideo(Long userId ,MultipartFile videoThumbnail, MultipartFile videoFile) throws IOException {
        //文件空判断
        if (videoThumbnail.isEmpty()||videoFile.isEmpty()){
            throw new BusinessException(ErrorResult.videoEmptyError());
        }
        //解析文件,获取文件名
        //将视频存储到fdfs
        String filename = videoFile.getOriginalFilename(); //adb.mp4
        //解析后缀获取文件类型
        String fileSuffix= filename.substring(filename.lastIndexOf(".")+1);//mp4
        //输入流,文件长度,文件类型,
        StorePath path = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), fileSuffix, null);
        //拼接访问路径
        String videoUrl = webServer.getWebServerUrl()+path.getFullPath();
        //将图片上传到阿里云
        //构建视频图片名称
        String videoPicName = videoThumbnail.getOriginalFilename();
        //上传图片
        String picUrl = ossTemplate.upLoading(videoPicName, videoThumbnail.getInputStream());
        //构建Video对象
        Video vi = new Video();
        vi.setUserId(userId);
        vi.setPicUrl(picUrl);
        vi.setVideoUrl(videoUrl);
        vi.setCreated(System.currentTimeMillis());
        vi.setText("林深时见鹿,海蓝时见鲸,梦醒时见你!");
       String videoId = videoApi.save(vi);
        messageService.sendLogMessage(userId,"0301","video",videoId);
       if (videoId.isEmpty()){
           throw new BusinessException(ErrorResult.error());
       }
    }

    /**
     * 推荐视频
     *
     * @param userId   用户id
     * @param page     页面
     * @param pageSize 页面大小
     * @return {@link PageResult}<{@link VideoVo}>
     */
    @Cacheable(value = "recommendVideo",key = "T(com.shawn.server.interceptor.ThreadContext).getUserId()+'_'+#page+'_'+#pageSize")
    public PageResult<VideoVo> recommendVideo(Long userId, Integer page, Integer pageSize) {
        //从redis获取该用户推荐的pid
        String vidKey = RC.VIDEO_RECOMMEND+userId;
        String vid = redisTemplate.opsForValue().get(vidKey);
        List<Video> list = new ArrayList<>();
        Integer count=0;
        if(Strings.isEmpty(vid)){
            //分页查询数据 不包含自己
            PageResult<Video> pageResult = videoApi.getVideos(page,pageSize,userId);
            list=pageResult.getItems();
            count=pageResult.getCounts();
        }else {
            //如果不为空,查询视频
            String[] vids = vid.split(",");
            count=vids.length;
            //判断当前页起始条数是否小于数据长度
            if((page-1)*pageSize<vids.length){
                List<Long> vidList = Arrays.stream(vids)
                        //跳过当前页码数量推荐id
                        .skip((long) (page - 1) *pageSize)
                        //限制获取数量
                        .limit(pageSize)
                        //转成Long类型
                        .map(Long::valueOf)
                        //用集合接收
                        .collect(Collectors.toList());
                //根据视频vid查询视频,不包含自己
                list=videoApi.getByIdList(vidList,userId);
            }
        }
        if (list.size()==0){
            return new PageResult<>();
        }
        //获取所有视频作者的id
        List<Long> ids = list.stream().map(Video::getUserId).collect(Collectors.toList());
        //根据id查询用户信息
        List<UserInfo> userInfos = userInfoApi.findByIds(ids);
        Map<Long, UserInfo> userInfoMap = CollUtil.fieldValueMap(userInfos, "id");
        //遍历video集合
        ArrayList<VideoVo> vos = new ArrayList<>();
        //构造当前用户hash key
        String userHashKey = RC.AUTEUR_FOCUS_HASH_KEY+userId;
        String likeKey = RC.VIDEO_LIKE_HASH_KEY+userId;
        for (Video video : list) {
            VideoVo vo = VideoVo.init(video, userInfoMap.get(video.getUserId()));
            //查询redis,判断当前用户是否已关注或点赞该条视频
            String videoKey = RC.VIDEO_INTERACT_KEY+video.getId().toHexString();
            String authorKey = RC.VIDEO_INTERACT_KEY+video.getUserId();
            Boolean focusRes = redisTemplate.opsForHash().hasKey(authorKey, userHashKey);
            Boolean likeRes = redisTemplate.opsForHash().hasKey(videoKey, likeKey);
            vo.setHasFocus(focusRes?1:0);
            vo.setHasLiked(likeRes?1:0);
            vos.add(vo);
            //查询redis判断当前用户是否已点赞该视频
        }
        return new PageResult<>(page,pageSize,count,vos);
    }

    /**
     * 是否点赞视频
     *
     * @param videoId   id
     * @param type 类型
     * @return {@link Integer} 当前视频点赞数量
     */
    @CacheEvict(value = "recommendVideo",allEntries = true) //视频更新点赞后删除所有视频缓存
    public Integer whetherLikeVideo(String videoId, Integer type) {
        Long userId = ThreadContext.getUserId();
        //查找当前redis该用户是否已点赞或是已取消点赞
        String videoKey = RC.VIDEO_INTERACT_KEY+videoId;
        String likeKey = RC.VIDEO_LIKE_HASH_KEY+userId;
        Boolean hasKey = redisTemplate.opsForHash().hasKey(videoKey, likeKey);
        if (Objects.equals(type, CommentType.LIKE.getType())&&hasKey){
            //赞而又赞
            throw new BusinessException(ErrorResult.likeError());
        }else if (Objects.equals(type, CommentType.DISLIKE.getType())&&!hasKey){
            //取消double
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //对视频表点赞数进行修改,并将点赞评论保存在评论表中
       Integer likeCount = videoApi.whetherLikeVideo(videoId,userId,type);
        //将点赞信息保存在redis或删除
        if(type.equals(1)){
            redisTemplate.opsForHash().put(videoKey,likeKey,"1");
        }else {
            redisTemplate.opsForHash().delete(videoKey,likeKey);
        }
        //记录用户行为日志
        messageService.sendLogMessage(userId,type.equals(1)?"0302":"0303","video",videoId);
        return likeCount;
    }

    /**
     * 发表评论
     *
     * @param userId  用户id
     * @param id      视频id
     * @param comment 评论
     * @return {@link Integer}
     */
    public Integer publishComment(Long userId, String id, String comment) {
        //直接生成评论
        Integer count = videoApi.publishComment(userId, id, comment);
        messageService.sendLogMessage(userId,"0304","video",id);
        return count;
    }


    /**
     * 关注作者
     *
     * @param userId   用户id
     * @param authorId 作者id
     */
    public void whetherFocusAuthor(Long userId, Long authorId,Integer type) {
        //查看redis
        String userHashKey = RC.AUTEUR_FOCUS_HASH_KEY+userId;
        String authorKey = RC.VIDEO_INTERACT_KEY+authorId;
        Boolean focusRes = redisTemplate.opsForHash().hasKey(authorKey, userHashKey);
        if (type.equals(1)&&focusRes){
            throw new BusinessException(ErrorResult.focusError());
        }else if (type.equals(0)&&!focusRes){
            throw new BusinessException(ErrorResult.cancelFocusError());
        }
        videoApi.whetherFocusAuthor(userId,authorId,type);
        //将关注信息保存在redis或删除
        if(type.equals(1)){
            redisTemplate.opsForHash().put(authorKey,userHashKey,"1");
        }else {
            redisTemplate.opsForHash().delete(authorKey,userHashKey);
        }
    }

    /**
     * 得到所有评论
     *
     * @param videoId  视频id
     * @param page     页面
     * @param pageSize 页面大小
     * @return {@link PageResult}<{@link CommentsVo}>
     */
    public PageResult<CommentsVo> getAllComments(String videoId, Integer page, Integer pageSize) {
       return commentsService.getAllComments(videoId,page,pageSize);
    }

    /**
     * 评论是否点赞
     *
     * @param userId 用户id
     * @param id     id
     * @param type   类型
     * @return {@link Integer}
     */
    public Integer commentWhetherLike(Long userId, String id, Integer type) {
      return  commentsService.commentWhetherLike(userId,id,type);
    }
}

